package hip.util.xml;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Element;
import org.dom4j.XPath;

public class XPathHelper {

    public static final String NS = "ns";

    public static Element selectNode(String path, Element ele) {
        if (path == null || path.isEmpty())
            return ele;
        XPath xpath = ele.createXPath(complementedXpath(path));
        Map<String, String> nsMap = new HashMap<String, String>();
        nsMap.put(NS, "urn:hl7-org:v3");
        xpath.setNamespaceURIs(nsMap);
        return (Element) xpath.selectSingleNode(ele);
    }

    @SuppressWarnings("rawtypes")
    public static List selectNodes(String path, Element ele) {
        XPath xpath = ele.createXPath(complementedXpath(path));
        Map<String, String> nsMap = new HashMap<String, String>();
        nsMap.put(NS, "urn:hl7-org:v3");
        xpath.setNamespaceURIs(nsMap);
        return xpath.selectNodes(ele);
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    @SuppressWarnings("rawtypes")
    public static Object[] getNodeValues(Element rootEle, String xpath, String attribute) {
        String[] xs = xpath.split("[?]");
        if (xs.length > 1) {
            String nx = "";
            for (int c = 1; c < xs.length; c++) {
                if (!nx.isEmpty())
                    nx += "?";
                nx += xs[c];
            }

            List ele = XPathHelper.selectNodes(xs[0], rootEle);
            Object[] os = new String[ele.size()];
            int i = 0;
            for (Object oei : ele) {
                Element ei = (Element) oei;
                if (xs.length == 2)
                    os[i] = getNodeValue(ei, nx, attribute);
                else
                    os[i] = getNodeValues(ei, nx, attribute);
                i++;
            }
            return os;
        } else {
            return new String[]{getNodeValue(rootEle, xpath, attribute)};
        }
    }

    // 查询某xpath下的某值
    public static String getNodeValue(Element rootEle, String xpath, String attribute) {
        Element ele = XPathHelper.selectNode(xpath, rootEle);
        if (ele != null) {
            if (attribute != null && !attribute.isEmpty())
                return ele.attributeValue(attribute);
            else
                return ele.getText();
        }
        return null;
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void setNodeValues(Element rootEle, String xpath, String attribute, Object[] values) {
        String[] xs = xpath.split("[?]");
        if (xs.length > 1) {
            String nx = "";
            for (int c = 1; c < xs.length; c++) {
                if (!nx.isEmpty())
                    nx += "?";
                nx += xs[c];
            }

            List elels = XPathHelper.selectNodes(xs[0], rootEle);
            if (elels.size() > 0) {
                if (values.length > elels.size()) {// 复制节点
                    for (int i = 0; i < values.length - elels.size(); i++) {
                        Element ei = (Element) elels.get(0);
                        Element ne = ei.createCopy();
                        List pc = ei.getParent().content();
                        pc.add(pc.indexOf(ei), ne);
                        ei.getParent().setContent(pc);
                    }
                } else if (values.length < elels.size()) {
                    for (int i = 0; i < elels.size() - values.length; i++) {
                        Element getParent = ((Element) elels.get(0)).getParent();
                        getParent.remove((Element) elels.get(i));
                    }
                }

                List ele = XPathHelper.selectNodes(xs[0], rootEle);
                int i = 0;
                for (Object oei : ele) {
                    Element ei = (Element) oei;
                    if (xs.length == 2)
                        setNodeValue(ei, nx, attribute, values[i].toString());
                    else
                        setNodeValues(ei, nx, attribute, (Object[]) values[i]);
                    i++;
                }
            }
        } else {
            setNodeValue(rootEle, xpath, attribute, values[0].toString());
        }

    }

    // 写入xpath下的某值
    public static void setNodeValue(Element rootEle, String xpath, String attribute, String value) {
        Element ele = XPathHelper.selectNode(xpath, rootEle);
        if (ele != null) {
            if (attribute != null && !attribute.isEmpty())
                ele.addAttribute(attribute, value);
            else {
                if (value != null && !value.isEmpty())
                    ele.addText(value);
            }
        }
    }

    public static String complementedXpath(String xpath) {
        String[] si = xpath.split("/");
        String nxpath = "";
        int c = 0;
        for (String s : si) {
            if (c > 0)
                nxpath += "/";
            if (s != null && !s.isEmpty())
                nxpath += XPathHelper.NS + ":" + s;
            c++;
        }
        return nxpath;
    }
}
